﻿using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.Json;
using Newtonsoft.Json.Linq;
using RQX.Common.Core.Extension;
using RQX.Common.Core.File;
using RQX.Common.Core.Logger;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace RQX.Common.Core.Config
{
    public static class ConfigUtils
    {
        #region Init & Build
        private static object configLock = new object();
        private static readonly string _defaultFileName = "appsettings.json";
        private static readonly string _defaultFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, _defaultFileName);
        private static IConfigurationBuilder _builder { get; set; }
        private static IConfigurationRoot _configRoot { get; set; }
        static ConfigUtils()
        {
            _builder = new ConfigurationBuilder();
            _builder.AddJsonFile(_defaultFileName, false, true);//默认配置文件
        }
        /// <summary>
        /// 添加json配置文件
        /// </summary>
        /// <param name="fileName"></param>
        public static IConfigurationBuilder AddConfigFile(string fileName) => _builder.AddJsonFile(fileName, false, true);
        /// <summary>
        /// 构建
        /// </summary>
        /// <returns></returns>
        public static void Build()
        {
            _configRoot = _builder.Build();
        }
        #endregion

        #region Root & Section
        /// <summary>
        /// 获取根配置
        /// </summary>
        /// <returns></returns>
        public static IConfigurationRoot GetConfigurationRoot() => _configRoot;
        /// <summary>
        /// 获取配置节
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static IConfigurationSection GetSection(this IConfigurationRoot configurationRoot, string key) => configurationRoot.GetSection(key);
        /// <summary>
        /// 获取配置节
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static IConfigurationSection GetSection(this IConfigurationSection configurationSection, string key) => configurationSection.GetSection(key);
        #endregion

        #region Value
        #region setValue
        /// <summary>
        /// 设置配置值
        /// </summary>
        /// <param name="configurationRoot"></param>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static void SetValue(this IConfigurationRoot configurationRoot,string key,object value)
        {
            configurationRoot[key] = value?.ToString();
        }
        /// <summary>
        /// 设置配置值
        /// </summary>
        /// <param name="configurationRoot"></param>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static void SetValue(this IConfigurationSection configurationSection, string key, object value)
        {
            configurationSection[key] = value?.ToString();
        }
        #endregion

        #region string
        /// <summary>
        /// 获取配置值
        /// </summary>
        /// <param name="configurationRoot"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string GetValue(this IConfigurationRoot configurationRoot, string key) => configurationRoot[key];
        /// <summary>
        /// 获取配置值
        /// </summary>
        /// <param name="configurationSection"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string GetValue(this IConfigurationSection configurationSection, string key) => configurationSection[key];
        #endregion
        #region int
        /// <summary>
        /// 获取配置值
        /// </summary>
        /// <param name="configurationRoot"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static int GetIntValue(this IConfigurationRoot configurationRoot, string key)
        {
            int.TryParse(configurationRoot[key], out var result);
            return result;
        }
        /// <summary>
        /// 获取配置值
        /// </summary>
        /// <param name="configurationSection"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static int GetIntValue(this IConfigurationSection configurationSection, string key)
        {
            int.TryParse(configurationSection[key], out var result);
            return result;
        }
        #endregion
        #region bool
        /// <summary>
        /// 获取配置值
        /// </summary>
        /// <param name="configurationRoot"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static bool GetBoolValue(this IConfigurationRoot configurationRoot, string key)
        {
            bool.TryParse(configurationRoot[key], out var result);
            return result;
        }
        /// <summary>
        /// 获取配置值
        /// </summary>
        /// <param name="configurationSection"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static bool GetBoolValue(this IConfigurationSection configurationSection, string key)
        {
            bool.TryParse(configurationSection[key], out var result);
            return result;
        }
        #endregion
        #region all
        /// <summary>
        /// 获取所有配置键值对
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<KeyValuePair<string, string>> GetAllConfigDic(this IConfigurationRoot configurationRoot) => configurationRoot.AsEnumerable();
        /// <summary>
        /// 获取所有配置键值对
        /// </summary>
        /// <param name="configurationSection"></param>
        /// <returns></returns>
        public static IEnumerable<KeyValuePair<string, string>> GetAllConfigDic(this IConfigurationSection configurationSection) => configurationSection.AsEnumerable();
        #endregion
        #endregion

        #region BuildClass
        /// <summary>
        /// 绑定配置到实体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="configurationSection"></param>
        /// <returns></returns>
        public static T BuildClass<T>(this IConfigurationRoot configurationRoot) where T : new()
        {
            var result = new T();
            configurationRoot.Bind(result);
            return result;
        }
        /// <summary>
        /// 绑定配置到实体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="configurationSection"></param>
        /// <returns></returns>
        public static T BuildClass<T>(this IConfigurationSection configurationSection) where T : new()
        {
            var result = new T();
            configurationSection.Bind(result);
            return result;
        }

        #endregion

        #region Save
        /// <summary>
        /// 保存配置到文件，只支持单文件
        /// </summary>
        public static void SaveToFile()
        {
            lock (configLock)
            {
                try
                {
                    var list = _configRoot.AsEnumerable().ToList();
                    int beginNum = 0;
                    int endNum = list.Count;
                    while (beginNum != endNum)
                    {
                        beginNum = endNum;
                        var keys = list.Select(k => k.Key);
                        list = list.Where(k => k.Value.IsNotNull() || keys.Any(m => m.StartsWith($"{k.Key}:"))).ToList();
                        endNum = list.Count;
                    }
                    var nodeList = list.Where(k => k.Key.IndexOf(":") == -1);
                    JObject root = new JObject();
                    nodeList.ForEach(item =>
                    {
                        var obj = BuildJsonTree(item, list);
                        root.Add(new JProperty(item.Key, obj));
                    });

                    var json = root.ToString();
                    FileUtils.SaveAllToFile(_defaultFilePath, json);
                }
                catch (Exception ex)
                {
                    LogUtils.WriteErrorLog($"保存配置报错！{ex}");
                }
            }
            
        }
        /// <summary>
        /// 构建树形json
        /// </summary>
        /// <param name="parent"></param>
        /// <param name="list"></param>
        /// <returns></returns>
        private static JToken BuildJsonTree(KeyValuePair<string, string> parent, List<KeyValuePair<string, string>> list)
        {
            var pIndex = parent.Key.Length;
            var childList = list.Where(k => k.Key.StartsWith($"{parent.Key}:") && k.Key.IndexOf(':', pIndex) == k.Key.LastIndexOf(':')).ToList();
            JObject node = new JObject();
            if (childList.Count() == 0) return parent.Value;
            childList.ForEach(item =>
            {
                var obj = BuildJsonTree(item, list);
                var cIndex = item.Key.LastIndexOf(':');
                node.Add(new JProperty(item.Key.Substring(cIndex + 1), obj));
            });
            return node;
        }
        #endregion
    }
}
